import json
import threading
import time
from datetime import datetime, timedelta
from evtx import PyEvtxParser
import re
import html
from xml.dom import minidom


class LogTransfer(threading.Thread):
    def __init__(self, mq, mac, interval=5):
        """
        日志传输线程，支持周期性同步和状态控制
        :param mq: 消息队列接口
        :param mac: 设备MAC地址
        :param interval: 同步间隔（秒）
        """
        super().__init__()
        self.__mq = mq
        self.__mac = mac
        self.__interval = interval
        self.__running = False
        self.__first_sync_completed = False  # 首次同步完成标志
        self.__security_log_path = r'C:\Windows\system32\winevt\Logs\Security.evtx'
        self.__system_log_path = r'C:\Windows\system32\winevt\Logs\System.evtx'

    def __get_log_info(self, event_path, event_id_to_filter=None, start_time=None, end_time=None):
        """
        解析EVTX日志文件，提取指定EventID和时间范围内的条目
        :param start_time: 开始时间（datetime对象），None表示不限制
        :param end_time: 结束时间（datetime对象），None表示不限制
        """
        parser = PyEvtxParser(event_path)
        pattern = re.compile(r'<EventID.*?(\d+)</EventID>')
        pattern_time = re.compile(r'<TimeCreated SystemTime="(.*?)"')
        event_list = []

        for record in parser.records():
            xml_data = record['data']
            res_event_id = re.findall(pattern, xml_data)
            res_time = re.findall(pattern_time, xml_data)

            if not res_event_id or not res_time:
                continue

            event_id = int(res_event_id[0])
            # 解析日志条目的时间戳
            try:
                # 格式示例: 2023-01-01T12:00:00.0000000Z
                log_time_str = res_time[0].replace('T', ' ').replace('Z', '')
                log_time = datetime.fromisoformat(log_time_str)
            except:
                continue

            # 筛选时间范围内的日志
            if (start_time and log_time < start_time) or (end_time and log_time > end_time):
                continue

            # 筛选EventID
            if event_id_to_filter is not None and event_id not in event_id_to_filter:
                continue

            # 转换为毫秒级时间戳（UTC+8）
            timestamp_ms = int(log_time.timestamp() * 1000) + 8 * 3600 * 1000

            r = {'event_id': event_id, 'timestamp': timestamp_ms, 'macAddress': self.__mac}
            xml_doc = minidom.parseString(xml_data)
            data_nodes = xml_doc.getElementsByTagName('Data')
            dict_data = {}

            for d in data_nodes:
                try:
                    name = d.getAttribute('Name')
                    value = html.unescape(d.childNodes[0].data)
                    dict_data[name] = value
                except Exception:
                    pass

            r['data'] = dict_data
            event_list.append(r)

        return event_list

    # 常见的安全事件ID：
    # 4624 - 成功登录事件，表示用户成功登录系统。
    # 4625 - 登录失败事件，表示用户尝试但未能成功登录系统。
    # 4634 - 注销事件，表示用户注销系统。
    # 4647 - 用户注销事件，表示用户通过重新启动或关闭计算机来注销系统。
    # 4720 - 创建用户事件，表示新用户帐户已创建。
    # 4722 - 启用用户帐户事件，表示禁用的用户帐户已被启用。
    # 4723 - 更改用户密码事件，表示用户密码已更改。
    # 4724 - 创建安全组事件，表示新安全组已创建。
    # 4728 - 成功授权事件，表示用户获得了指定对象的权限。
    # 4738 - 设置用户密码事件，表示用户密码已更改或重置。
    # 4726 - 删除用户
    # 常见的系统事件ID：
    # 1074 - 通过这个事件ID查看计算机的开机、关机、重启的时间以及原因和注释。
    # 6005 - 表示计算机日志服务已启动，如果出现了事件ID为6005，则表示这天正常启动了系统。
    # 6006 - 系统关闭
    # 6008 - 非正常关机
    # 6009 - 系统已经重新启动
    # 6013 - 系统已经重新启动，原因是操作系统版本升级
    # 7036 - 服务状态更改
    # 7040 - 启动或停止监视者通知
    # 7045 - 安装服务
    # 日志清除事件：
    # 1102 - 这个事件ID记录所有审计日志清除事件，当有日志被清除时，出现此事件ID。
    def __get_account_log(self, start_time=None, end_time=None):
        """获取账号相关日志（登录、用户管理等）"""
        event_ids = [4624, 4625, 4634,4647,4720,4722,4726, 4723,4724,4728,4726]
        return self.__get_log_info(self.__security_log_path, event_ids, start_time, end_time)

    def __get_system_log(self, start_time=None, end_time=None):
        """获取系统服务相关日志"""
        event_ids = [1074,6005,6006,6008,6009,6013,7036,7040, 7045, 1102]
        return self.__get_log_info(self.__system_log_path, event_ids, start_time, end_time)

    def start_sync(self):
        """启动日志同步服务"""
        self.__running = True
        self.start()
        print("日志同步服务已启动")

    def stop_sync(self):
        """停止日志同步服务"""
        self.__running = False
        print("日志同步服务已停止")

    def is_running(self):
        """检查服务运行状态"""
        return self.__running

    def run(self):
        """周期性执行日志收集与发送"""
        while self.__running:
            try:
                current_time = datetime.now()
                # 首次同步逻辑 - 收集近72小时日志
                if not self.__first_sync_completed:
                    print("开始首次同步（近72小时日志）...")
                    start_time = current_time - timedelta(hours=12)
                    end_time = current_time

                    # 获取时间范围内的日志
                    account_log = self.__get_account_log(start_time, end_time)
                    system_log = self.__get_system_log(start_time, end_time)
                    all_log = account_log + system_log

                    if all_log:
                        data = json.dumps(all_log)
                        self.__mq.produce_log_data(data)
                        print(data)
                        print(f"首次同步完成: 账号{len(account_log)}条, 系统{len(system_log)}条")
                    else:
                        print("首次同步: 该时间段无日志")

                    self.__first_sync_completed = True
                    print(f"首次同步完成，接下来每{self.__interval}秒同步一次近{self.__interval}秒的日志")

                # 常规同步逻辑 - 收集近interval秒日志
                else:
                    start_time = current_time - timedelta(seconds=self.__interval)
                    end_time = current_time

                    print(
                        f"开始常规同步: {start_time.strftime('%Y-%m-%d %H:%M:%S')} 至 {end_time.strftime('%Y-%m-%d %H:%M:%S')}")

                    # 获取时间范围内的日志
                    account_log = self.__get_account_log(start_time, end_time)
                    system_log = self.__get_system_log(start_time, end_time)
                    all_log = account_log + system_log

                    if all_log:
                        data = json.dumps(all_log)

                        self.__mq.produce_log_data(data)
                        print(f"常规同步完成: 账号{len(account_log)}条, 系统{len(system_log)}条")
                    else:
                        print("常规同步: 该时间段无新日志")

                # 等待下一个周期
                for i in range(self.__interval, 0, -1):
                    if not self.__running:
                        return
                    time.sleep(1)

            except Exception as e:
                print(f"日志同步出错: {str(e)}")
                # 出错后等待一段时间再重试
                time.sleep(5)